<script lang="ts">
    import Portal from "svelte-portal";
    import { createUniqueId } from "../utils/createUniqueId";
    import { useClassList } from "../utils/useClassList";
    import usezIndex from "../utils/usezIndex";
    import type { ModalProps } from "./Modal";
    import { Draggable } from "../Draggable";
    import Icon from "../Common/Icons/Icon.svelte";
    import usePortal from "../utils/usePortal";
    import { Button } from "../Button";
    import { useStyle } from "../utils/useStyle";
    import { useTransition } from "../utils/useTransition";
    import { Tween } from "svelte/motion";
    import { cubicOut } from "svelte/easing";
    import { _ } from "svelte-i18n";

    let wrap: any;
    let maskEle: HTMLElement | undefined = $state();
    let draggable: any;
    let setOverflow = false;
    let originOverflow = "";

    let { visible = $bindable(false), draggale = true, ...props }: ModalProps = $props();
    let loading = $state(false);
    let opened = $state(false);
    let destroyed = $state(false);

    const footerAlign = props.footerAlign ?? "end";
    const footerReverse = props.footerReverse ?? false;
    const okButtonType = props.okButtonType ?? "primary";
    const cancleButtonType = props.cancleButtonType ?? "default";

    const classList = $derived(useClassList(props, "cm-modal"));
    const zindex = usezIndex();

    const id = "cm-modal-portal";
    const footer = props.footer ?? true;
    const hasCloseIcon = props.hasCloseIcon ?? true;
    const modalId = createUniqueId();
    const okText = $derived(props.okText || $_("Modal.okText"));
    const cancleText = $derived(props.cancleText || $_("Modal.cancelText"));
    const mask = props.mask ?? true;
    const maskClosable = props.maskClosable ?? true;
    const resetPostion = props.resetPostion ?? false;

    const transition = useTransition({
        el: () => wrap,
        startClass: "cm-modal-visible",
        activeClass: "cm-modal-open",
        enterEndClass: "cm-modal-opened",
        onLeave: () => {
            opened = false;
            if (props.destroyOnClose) {
                destroyed = true;
            }
        },
        onEnter: () => {
            opened = true;
        },
    });

    $effect(() => {
        const v = visible;
        if (v) {
            if (props.destroyOnClose) {
                destroyed = false;
            }
            scale.set(1);
            transition.enter();
        } else {
            scale.set(0);
            transition.leave();
        }
    });

    const wrapClass = $derived({
        "cm-modal-wrap": true,
    });

    $effect(() => {
        if (props.fullScreen) {
            wrap.classList.add("cm-modal-fullscreen");
        } else {
            wrap.classList.remove("cm-modal-fullscreen");
        }
    });

    const maskClass = $derived({
        "cm-modal-mask": true,
        "cm-modal-mask-visible": visible,
    });

    const onClickClose = () => {
        props.onclickclose?.();
        onClose();
    };

    const onClose = () => {
        props.onclosed?.();
        visible = false;
    };

    const onCancel = () => {
        onClose();
        props.oncancel?.();
    };

    const onOk = async () => {
        // 先判断显示loading
        if (props.loading) {
            if (!loading) {
                loading = true;
            }
        }
        // 如果存在onOK回调判断是否返回值
        if (props.onok) {
            const ret = await props.onok?.();
            // 没有返回值并且非loading直接关闭
            if (ret === undefined && !loading) {
                onClose();
            }
            // 返回true直接关闭
            if (ret === true) {
                onClose();
            }
            // 返回false，重置loading
            if (ret === false) {
                loading = false;
            }
        } else {
            if (!loading) {
                onClose();
            }
        }
    };

    $effect(() => {
        const show = opened;
        if (!show) {
            loading = false;
            if (setOverflow) {
                document.body.style.overflow = originOverflow;
                setOverflow = false;
            }
        } else {
            if (wrap) {
                const wrapH = wrap.getBoundingClientRect().height;
                const contentH = wrap.children[0].getBoundingClientRect().height;
                // 超出显示内容
                if (contentH > wrapH) {
                    wrap.style.overflow = "auto";
                    wrap.children[0].style.top = 0;
                    const bodyStyle = window.getComputedStyle(document.body, null);
                    originOverflow = bodyStyle.overflow;
                    if (originOverflow !== "hidden") {
                        document.body.style.overflow = "hidden";
                        setOverflow = true;
                    }
                } else {
                    wrap.style.overflow = "none";
                    setOverflow = false;
                }
                setTimeout(() => {
                    wrap.focus();
                }, 300);
            }
            if (resetPostion) {
                if (draggable) {
                    draggable.reset();
                }
            }
        }
    });

    const onMaskClick = (e: any) => {
        if (maskClosable) {
            if (e.target === maskEle) {
                visible = false;
            }
        }
    };

    const onkeydown = (e: any) => {
        // e.preventDefault && e.preventDefault();
        // e.stopPropagation && e.stopPropagation();
        if (e.keyCode === 27) {
            visible = false;
        }
    };

    let scale = new Tween(0, {
        duration: 250,
        easing: cubicOut,
    });

    const defaultStyle = $derived.by(() => {
        return useStyle({}, props.defaultPosition as Record<string, string>);
    });
</script>

<Portal target={usePortal(id, id)}>
    {#if mask}
        <!-- svelte-ignore a11y_click_events_have_key_events -->
        <!-- svelte-ignore a11y_no_static_element_interactions -->
        <div class={maskClass} onclick={onMaskClick} bind:this={maskEle} style={`z-index: ${zindex - 1}`}></div>
    {/if}
    <!-- svelte-ignore a11y_positive_tabindex -->
    <!-- svelte-ignore a11y_no_static_element_interactions -->
    <div class={wrapClass} bind:this={wrap} tabIndex="0" {onkeydown} style={`z-index: ${zindex}`}>
        <Draggable bind:this={draggable} bounds={props.bounds || "body"} style={defaultStyle} handle={'.cm-modal-header[data-id="' + modalId + '"]'} disabled={!draggale}>
            <div class={classList} style={props.style} style:transform={`scale(${scale.current})`}>
                <div class={{ "cm-modal-header": true, "cm-modal-header-noDrag": !draggale }} style={props.headerStyle} data-id={`${modalId}`}>
                    {#if props.title}
                        <div class="cm-modal-title">
                            {#if typeof props.title === "function"}
                                {@render props.title()}
                            {:else}
                                {props.title}
                            {/if}
                        </div>
                    {/if}
                    {#if hasCloseIcon}
                        <!-- svelte-ignore a11y_click_events_have_key_events -->
                        <span class="cm-modal-close" onclick={onClickClose}>
                            {#if props.closeIcon}
                                {@render props.closeIcon?.()}
                            {:else}
                                <Icon icon="times" />
                            {/if}
                        </span>
                    {/if}
                </div>
                <div class="cm-modal-body" style={props.bodyStyle}>
                    {#if !destroyed}
                        {@render props.children?.()}
                    {/if}
                </div>
                {#if footer}
                    <div
                        class={{
                            "cm-modal-footer": true,
                            "cm-modal-footer-reverse": footerReverse,
                            [`cm-modal-footer-${footerAlign}`]: !!footerAlign,
                        }}
                    >
                        <Button type={okButtonType} {loading} onclick={onOk}>{okText}</Button>
                        {#if !props.hideCancle}
                            <Button type={cancleButtonType} onclick={onCancel}>{cancleText}</Button>
                        {/if}
                    </div>
                {/if}
            </div>
        </Draggable>
    </div>
</Portal>
